<template>
  <div class="tree-graph-container">
    <div class="flex">
      <el-button @click="test5">vertices:路径点</el-button>
      <el-button @click="test6">orth:正交路由</el-button>
      <el-button @click="test7">oneSide:正交路由 'orth' 的受限版本</el-button>
      <el-button @click="test8">manhattan：曼哈顿路由</el-button>
      <el-button @click="test9">metro：地铁路由</el-button>
      <el-button @click="test10">er</el-button>
      <el-button @click="test11">自定义路由</el-button>
    </div>

    <div class="flex flex-row">
      <!-- 1. x6 容器 -->
      <div id="x6Container" ref="containerRef"></div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, shallowRef } from "vue";
import { Graph, Point, EdgeView } from "@antv/x6";
import { Export } from "@antv/x6-plugin-export";

let graph: Graph | null = null;

// x6 图的实例
const graphInstance = shallowRef();

const containerRef = ref();

// 注册自定义路由
interface RandomRouterArgs {
  bounces?: number;
}

function randomRouter(vertices: Point.PointLike[], args: RandomRouterArgs, view: EdgeView) {
  const bounces = args.bounces || 20;
  const points = vertices.map(p => Point.create(p));

  for (let i = 0; i < bounces; i++) {
    const sourceCorner = view.sourceBBox.getCenter();
    const targetCorner = view.targetBBox.getCenter();
    const randomPoint = Point.random(sourceCorner.x, targetCorner.x, sourceCorner.y, targetCorner.y);
    points.push(randomPoint);
  }

  return points;
}

Graph.registerRouter("random", randomRouter);

const test5 = () => {
  graph.addEdge({
    source: { x: 600, y: 100 },
    target: { x: 600, y: 500 },
    // 路径点
    vertices: [
      { x: 550, y: 200 },
      { x: 550, y: 350 }
    ]
  });
};

const test6 = () => {
  graph.addEdge({
    source: { x: 600, y: 100 },
    target: { x: 600, y: 500 },
    // 路径点
    vertices: [
      { x: 550, y: 200 },
      { x: 550, y: 350 }
    ],
    // 1、正交路由 orth https://x6.antv.vision/zh/docs/api/registry/router#orth
    router: {
      name: "orth",
      args: {}
    }
  });
};

const test7 = () => {
  graph.addEdge({
    source: { x: 600, y: 100 },
    target: { x: 600, y: 500 },
    // 不推荐路径点
    // vertices: [
    //   { x: 550, y: 200 },
    //   { x: 550, y: 350 },
    // ],
    //2、oneSide 路由是正交路由 'orth' 的受限版本，该路生成一个严格的三段路由：从起始节点的 side 侧开始，经过中间段，再从终止节点的 side 侧结束路由。需要特别注意的是，使用该路由时请不要同时指定 vertices，否则路由效果会非常差。
    router: {
      name: "oneSide",
      args: { side: "right" } // 'left' | 'right' | 'top' | 'bottom'
    }
  });
};

const test8 = () => {
  graph.addNode({
    id: "barrier",
    x: 700,
    y: 200,
    width: 80,
    height: 40,
    label: "障碍节点"
  });
  graph.addEdge({
    source: { x: 700, y: 100 },
    target: { x: 700, y: 500 },
    // 路径点
    // vertices: [
    //   { x: 650, y: 200 },
    //   { x: 650, y: 350 },
    // ],
    // 3、manhattan 曼哈顿路由 'manhattan' 路由是正交路由 'orth' 的智能版本，该路由由水平或垂直的正交线段组成，并自动避开路径上的其他节点（障碍）。
    router: {
      name: "manhattan"
      // args: {
      //   startDirections: ['top'],
      //   endDirections: ['bottom'],
      // },
    }
  });
};

const test9 = () => {
  graph.addEdge({
    source: { x: 800, y: 100 },
    target: { x: 800, y: 500 },
    // 路径点
    vertices: [
      { x: 850, y: 200 },
      { x: 850, y: 350 }
    ],
    // 4、地铁路由 'metro' 是曼哈顿路由 manhattan 的一个变种，它由水平或垂直的正交线段和斜角线段组成，类似地铁轨道图，并自动避开路径上的其他节点（障碍）。其选项与 manhattan 路由一样，但 maxDirectionChange 的默认值为 45，表示路由线段的最大倾斜角度为 45 度。
    router: {
      name: "metro",
      args: {
        maxDirectionChange: 100 // 默认45
        // startDirections: ['top'],
        // endDirections: ['bottom'],
      }
    }
  });
};

const test10 = () => {
  graph.addEdge({
    source: { x: 850, y: 100 },
    target: { x: 850, y: 500 },
    // 路径点
    vertices: [
      { x: 900, y: 200 },
      { x: 900, y: 350 }
    ],
    // 5、实体关系路由 'er' 由 Z 字形的斜角线段组成，常用于表示 ER 图中的实体之间的连线。
    router: {
      name: "er",
      args: {
        // 路由的第一个点和最后一个点与节点之间的距离。当取值为 'center' 时，节点距离的中心作为路由点坐标。
        offset: 32,
        // 路由的第一个点和最后一个点与节点之间的最小距离。
        min: 16,
        // 路由方向，缺省时将自动选择最优方向。'T' | 'B' | 'L' | 'R' | 'H' | 'V'
        direction: undefined
      }
    }
  });
};

const test11 = () => {
  graph.addEdge({
    source: { x: 900, y: 100 },
    target: { x: 900, y: 500 },
    // 路径点
    vertices: [
      { x: 950, y: 200 },
      { x: 950, y: 350 }
    ],
    // 6、自定义路由
    router: {
      name: "random",
      args: {
        bounces: 3
      }
    }
  });
};

// 1.初始化数据
const originalData = ref({
  // 节点
  nodes: [],
  // 边
  edges: []
});
// 2.初始化画布
const init = () => {
  // 初始化 x6 图背景板
  // 创建一个新的 Graph 实例
  graph = new Graph({
    // 指定 Graph 的容器元素
    container: document.getElementById("x6Container")!,

    // 自动调整 Graph 的大小以适应容器
    autoResize: true,

    // 设置背景颜色
    background: {
      color: "#fffbe6" // 设置画布背景颜色
    },
    // 网格设置
    grid: {
      visible: true, // 渲染网格背景
      size: 10, // 网格大小 10px
      type: "doubleMesh",
      args: [
        {
          color: "#eee", // 主网格线颜色
          thickness: 1 // 主网格线宽度
        },
        {
          color: "#ddd", // 次网格线颜色
          thickness: 1, // 次网格线宽度
          factor: 4 // 主次网格线间隔
        }
      ]
    },

    // 滚动设置
    scroller: {
      enabled: false, // 启用滚动
      pannable: true // 允许通过拖动来平移视图
    },

    // 是否启用缩略图（小地图）
    minimap: false, // 禁用缩略图

    // 鼠标滚轮设置
    mousewheel: {
      enabled: true, // 启用鼠标滚轮缩放
      modifiers: ["ctrl", "meta"] // 可以通过按下 Ctrl 或 Meta 键来启用缩放
    },

    // 平移设置
    panning: {
      enabled: true, // 启用平移功能
      modifiers: "space" // 需要按住 space 键才能进行拖拽平移 大空格键
    },

    // 交互设置(拖拽移动)
    interacting: {
      nodeMovable: true
    },

    // 拖拽设置
    dragging: {
      enabled: true, // 启用拖拽功能
      ghost: false // 禁用拖拽时的虚影效果
    },

    // 当源/目标是画布上的点时，需要开启 allowBlank 选项（默认已经开启）才能生效
    connecting: {
      allowBlank: false
    }
  });

  // 渲染
  graph.fromJSON(originalData.value);
  graph.zoomToFit(); // 缩放
  graph.scale(0.7); // 设置初始缩放比例，例如 0.7 表示缩小到 70%
  // graph.centerContent(); // 居中
  graph.use(new Export()); // 加载导出插件
  graphInstance.value = graph; // 保存图实例
};

onMounted(() => {
  init(); // 初始化树数据
});
</script>

<style scoped>
#x6Container {
  flex: 1;
  width: 100%;
  height: 100vh;
  position: relative;
}
</style>
